/**
 *******************************************************************************
 * @file  usb_dev_audio_out_itf.c
 * @brief Audio class for USB device
 @verbatim
   Change Logs:
   Date             Author          Notes
   2021-03-29       Linsq           First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by HDSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "usb_dev_audio_class.h"
#include "usb_dev_audio_out_itf.h"

/** @defgroup usbd_audio_out_if_Private_FunctionPrototypes
  * @{
  */
void     play_init         (void);
void     play_deinit       (void);
uint8_t  play_audiocmd     (uint8_t* pbuf, uint32_t size, uint8_t cmd);
uint8_t  play_volumectrl   (uint8_t vol);
uint8_t  play_mutectrl     (uint8_t cmd);
uint8_t  play_periodictc   (uint8_t cmd);
uint8_t  play_getstate     (void);

/**
  * @}
  */ 

/** @defgroup usbd_audio_out_if_Private_Variables
  * @{
  */ 
AUDIO_FOPS_TypeDef  AUDIO_OUT_fops = 
{
  play_init,
  play_deinit,
  play_audiocmd,
  play_volumectrl,
  play_mutectrl,
  play_periodictc,
  play_getstate
};

static uint8_t AudioState = AUDIO_STATE_INACTIVE;


/**
 *******************************************************************************
 ** \brief  initialize resources requered by the audio play function
 ** \retval none
 ******************************************************************************/
void play_init(void)
{
    static uint32_t Initialized = 0;

    /* Check if the low layer has already been initialized */
    if (Initialized == 0)
    {
        Codec_Init();
        /* Set the Initialization flag to prevent reinitializing the interface again */
        Initialized = 1;
    }

    /* Update the Audio state machine */
    AudioState = AUDIO_STATE_ACTIVE;
}

/**
 *******************************************************************************
 ** \brief  deinit all resources required by audio recorder function
 ** \param  none
 ** \retval none
 ******************************************************************************/
void play_deinit(void)
{
    /* Update the Audio state machine */
    AudioState = AUDIO_STATE_INACTIVE;
}

/**
 *******************************************************************************
 ** \brief  control the current stream,such as play, stop, pause or resume, etc.
 ** \param  pbuf: address from which buffer should be played
 ** \param  size: size of the current buffer in bytes
 ** \param  cmd: the command to be executed
 ** \retval status
 ******************************************************************************/
uint32_t playbuf[96];
uint8_t play_audiocmd(uint8_t* pbuf, uint32_t size, uint8_t cmd)
{
    uint16_t tmp1, tmp2;
    /* Check the current state */
    if ((AudioState == AUDIO_STATE_INACTIVE) || (AudioState == AUDIO_STATE_ERROR))
    {
        AudioState = AUDIO_STATE_ERROR;
        return AUDIO_FAIL;
    }

  switch (cmd)
  {
    /* Process the PLAY command ----------------------------*/
  case AUDIO_CMD_PLAY:
    /* If current state is Active or Stopped */
    if ((AudioState == AUDIO_STATE_ACTIVE) || \
       (AudioState == AUDIO_STATE_STOPPED) || \
       (AudioState == AUDIO_STATE_PLAYING))
    {
        /* Copy the data received from USB to the playbuf and send to the I2S */
        tmp2 = 0;
        for(tmp1 = 0; tmp1 < AUDIO_IN_SAMPLE_NUM; tmp1++)
        {
            playbuf[tmp1] = *((uint32_t *)&pbuf[tmp2]);
            playbuf[tmp1] = playbuf[tmp1]&0x00ffffff;      //Set the high byte(bit24-bit31) to be zero
            tmp2 += 3;
        }
        
      Audio_MAL_Play(playbuf, size);
      AudioState = AUDIO_STATE_PLAYING;
      return AUDIO_OK;
    }
    /* If current state is Paused */
    else if (AudioState == AUDIO_STATE_PAUSED)
    {
        Audio_MAL_PauseResume(AUDIO_RESUME);
        AudioState = AUDIO_STATE_PLAYING;
        return AUDIO_OK;
    } 
    else /* Not allowed command */
    {
      return AUDIO_FAIL;
    }
    
    /* Process the STOP command ----------------------------*/
  case AUDIO_CMD_STOP:
    if (AudioState != AUDIO_STATE_PLAYING)
    {
      /* Unsupported command */
      return AUDIO_FAIL;
    }
    else
    {
        Audio_MAL_Stop();
        AudioState = AUDIO_STATE_STOPPED;
        return AUDIO_OK;
    }
  
    /* Process the PAUSE command ---------------------------*/
  case AUDIO_CMD_PAUSE:
    if (AudioState != AUDIO_STATE_PLAYING)
    {
      /* Unsupported command */
      return AUDIO_FAIL;
    }
    else
    {
        Audio_MAL_PauseResume(AUDIO_RESUME);
        AudioState = AUDIO_STATE_PAUSED;
        return AUDIO_OK;
    } 
    
    /* Unsupported command ---------------------------------*/
  default:
    return AUDIO_FAIL;
  }  
}

/**
 *******************************************************************************
 ** \brief  set the volume level in percentage
 ** \param  vol: between 0 and 100 
 ** \retval status
 ******************************************************************************/
uint8_t play_volumectrl(uint8_t vol)
{
    /* Call low layer volume setting function */  
    if (AUDIO_VolumeCtl(vol) != 0)
    {
        AudioState = AUDIO_STATE_ERROR;
        return AUDIO_FAIL;
    }
    return AUDIO_OK;
}

/**
 *******************************************************************************
 ** \brief  the command to mute or unmute the audio player
 ** \param  cmd: command
 ** \retval status
 ******************************************************************************/
uint8_t play_mutectrl(uint8_t cmd)
{
    //TODO
    return AUDIO_OK;
}

/**
 *******************************************************************************
 ** \brief  option control function
 ** \param  cmd: command
 ** \retval status
 ******************************************************************************/
uint8_t play_periodictc(uint8_t cmd)
{
    //TODO
    return AUDIO_OK;
}

/**
 *******************************************************************************
 ** \brief  get the current state of the audio player
 ** \param  none
 ** \retval status
 ******************************************************************************/
uint8_t play_getstate(void)
{
    //TODO
    return AudioState;
}
